<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
</head>
<body>
  <script type="text/javascript">
    // 简易 Promise 实现
    /*
      首先我们创建了三个常量表示状态
      对于经常使用的一些值都应该通过常量来管理
      便于开发及后期维护
    */
    const PENDING = 'pending'
    const RESOLVED = 'resolved'
    const REJECTED = 'rejected'

    function MyPromise(fn) {
      /*
        在函数体内部首先创建了常量 that
        因为代码可能会异步执行
        用于获取正确的 this 对象
      */
      const that = this
      // 一开始 Promise 的状态应该是 pending
      that.state = PENDING
      // value 变量用于保存 resolve 或者 reject 中传入的值
      that.value = null
      /*
        resolvedCallbacks 和 rejectedCallbacks 用于保存 then 中的回调
        因为执行完 Promise 时状态可能还是等待中
        这时候应该把 then 中的回调保存起来用于状态改变时使用
      */
      // Promise resolve 时的回调函数集
      that.resolvedCallbacks = []
      // Promise reject 时的回调函数集
      that.rejectedCallbacks = []

      function resolve(value) {
        // 判断当前状态中是否为等待中
        // 只有等待中才可以改变状态
        if (that.state === PENDING) {
          // 将当前状态改为对应状态
          that.state = RESOLVED
          // 将传入的值赋值给 value
          that.value = value
          // 遍历回调数组并执行
          that.resolvedCallbacks.map(cb => cb(that.value))
        }
      }
      // 同上
      function reject(value) {
        if (that.state === PENDING) {
          that.state = REJECTED
          that.value = value
          that.rejectedCallbacks.map(cb => cb(that.value))
        }
      }
      // 执行传入 Promise 中的函数
      /*
        考虑到执行 fn 过程中有可能出错
        所以我们用 try/catch 块给包起来
        并且在出错后以 catch 到的值 reject 调这个 promise
      */
      try {
        fn(resolve, reject)
      } catch (e) {
        reject(e)
      }
    }
    // 添加 then 方法
    MyPromise.prototype.then = function(onFulfilled, onRejected) {
      const that = this
      // then 的两个可选参数
      // 判断两个参数是否为函数类型, 因为这两个参数是可选参数
      // 当参数不是函数类型时，需要创建一个函数复制给对应的参数，同事也实现了透传
      onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : v => v
      onRejected = typeof onRejected === 'function' ? onRejected : r => { throw r }
      // 如果是等待状态 那就将回调方法 放入 回调数组中等待执行
      if (that.state === PENDING) {
        that.rejectedCallbacks.push(onFulfilled)
        that.rejectedCallbacks.push(onRejected)
      }
      // 如果是 resolved(完成) 状态 执行onFulfilled()
      if (that.state === RESOLVED) {
        onFulfilled(that.value)
      }
      // 如果是 rejected(拒绝) 状态 执行onRejected()
      if (that.state === REJECTED) {
        onRejected(that.value)
      }
    }
    // 测试
    new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve(1)
      }, 0)
    }).then(value => {
      console.log(value)
    })
  </script>
</body>
</html>